global labyrinth_maker_rlt

fn get_status arr x y z =
(
	if x > 0 and y > 0 and z > 0 and x <= arr.count and y <= arr[1].count and z <= arr[1][1].count then
	(
		return arr[x][y][z]
	)
	else
	(
		return false
	)
)

fn set_status arr x y z status = 
(
	arr[x][y][z] = status
)

fn find_free arr x y z =
(
	local result = #()
	local arr_st = #(
		#((get_status arr x (y + 1) z), #(x, (y + 1), z)),
		#((get_status arr (x + 1) y z), #((x + 1), y, z)),
		#((get_status arr x (y - 1) z), #(x, (y - 1), z)),
		#((get_status arr (x - 1) y z), #((x - 1), y, z)),
		#((get_status arr x y (z + 1)), #(x, y, (z + 1))),
		#((get_status arr x y (z - 1)), #(x, y, (z - 1)))
	)
	
	for s in arr_st where s[1] != false do
	(
		append result s[2]
	)
	
	result = if result.count > 0 then 
	(
		result[random 1 result.count]
	) else false
	
	return result
)

fn create_shape arr trail first_pos init_p = 
(
	local xcount = labyrinth_maker_rlt.spn2.value
	local ycount = labyrinth_maker_rlt.spn3.value
	local zcount = labyrinth_maker_rlt.spn4.value
	local xsize = labyrinth_maker_rlt.spn5.value
	local ysize = labyrinth_maker_rlt.spn6.value
	local zsize = labyrinth_maker_rlt.spn7.value
	local vp_step_upd = labyrinth_maker_rlt.spn8.value
	local show_in_vp = labyrinth_maker_rlt.chk1.state
	
	local total_free_cell = (arr.count * arr[1].count * arr[1][1].count - (init_p - 1))
	local vp_step_iter = 0
	local TrailIter = 1
		
	local last_pos = #()
	local first_sp_pos = #()
	local shapes_arr = #()
	local point_trail = #()
	
	for i in first_pos do
	(
		append first_sp_pos [(i[1] * xsize - (xsize * xcount / 2. + (xsize / 2.))), (i[2] * ysize - (ysize * ycount / 2. + (ysize / 2.))), (i[3] * zsize - zsize)]
	)
	
	if show_in_vp then 
	(
		for i in first_sp_pos do 
		(
			local pt = point pos:i size:((xsize + ysize)/2.) box:true wirecolor:green
			append point_trail pt
		)
	)
	
	delete $labyrinth_temp*
	if init_p > 1 then 
	(
		for i = 1 to init_p do 
		(
			local sp_color = red
			sp_color.hue = (random 0 255)
			sp = splineshape name:"labyrinth_temp" wirecolor:sp_color
			append shapes_arr #(sp,1)
		)
	)
	else
	(
		sp = splineshape name:"labyrinth_temp"
		append shapes_arr #(sp,1)
	)
	
	for i = 1 to shapes_arr.count do
	(
		addnewspline shapes_arr[i][1]
		addknot shapes_arr[i][1] shapes_arr[i][2] #corner #curve first_sp_pos[i]
	)

	while total_free_cell > 1 do
	(
		for t in trail do
		(
			if t.count > 0 then
			(
				local check = (find_free arr t[t.count][1] t[t.count][2] t[t.count][3])
				local trail_pos = [(t[t.count][1] * xsize - (xsize * xcount / 2. + (xsize / 2.))), (t[t.count][2] * ysize - (ysize * ycount / 2. + (ysize / 2.))), (t[t.count][3] * zsize - zsize)]
				
				if check != false then 
				(
					total_free_cell -= 1
					local check_pos = [(check[1] * xsize - (xsize * xcount / 2. + (xsize / 2.))), (check[2] * ysize - (ysize * ycount / 2. + (ysize / 2.))), (check[3] * zsize - zsize)]

					if last_pos[TrailIter] == false then
					(
						shapes_arr[TrailIter][2] += 1
						addnewspline shapes_arr[TrailIter][1]
						addknot shapes_arr[TrailIter][1] shapes_arr[TrailIter][2] #corner #curve trail_pos
					)
					set_status arr check[1] check[2] check[3] false
					append t check
									
					addknot shapes_arr[TrailIter][1] shapes_arr[TrailIter][2] #corner #curve check_pos
					
					if show_in_vp then
					(
						point_trail[TrailIter].pos = check_pos
						if point_trail[TrailIter].wirecolor == red then
						(
							point_trail[TrailIter].wirecolor = green
						)
					)
				) 
				else 
				(
					set_status arr t[t.count][1] t[t.count][2] t[t.count][3] false
					deleteitem t t.count
					if show_in_vp then
					(
						point_trail[TrailIter].pos = trail_pos
						point_trail[TrailIter].wirecolor = red
					)
				)
				
				last_pos[TrailIter] = check
			)
			else 
			(
				if show_in_vp then
				(
					hide point_trail[TrailIter]
				)
			)
			TrailIter += 1
			TrailIter = if TrailIter > init_p then 1 else TrailIter
			vp_step_iter + 1
		)
		
		if show_in_vp then
		(
			local numK
			local numS
			local getK = #()
			if vp_step_iter > vp_step_upd then
			(
				for s in shapes_arr do
				(
					if (numknots s[1]) > 1 then
					(
						updateshape s[1]
						numS = (NumSplines s[1])
						numK = (NumKnots s[1] numS)
						append getK (GetKnotPoint s[1] numS numK)
					)
				)
				max views redraw
				vp_step_iter = 0
			)
		)
		vp_step_iter += 1
		if KeyBoard.EscPressed then exit()
	)
	
	try(delete point_trail) catch()
	
	for s in shapes_arr do
	(
		if (numknots s[1]) > 1 then
		(
			updateshape s[1]
			centerPivot s[1]
			max views redraw
		)
	)
)

fn start_gen = 
(
	local num_of_init_pt = labyrinth_maker_rlt.spn1.value
	local xcount = labyrinth_maker_rlt.spn2.value
	local ycount = labyrinth_maker_rlt.spn3.value
	local zcount = labyrinth_maker_rlt.spn4.value
	local arr_cell = for x = 1 to xcount collect 
	(
		for y = 1 to ycount collect 
		(
			for z = 1 to zcount collect true
		)
	)
	local arr_trail = #()
	local StartPos = #()
	
	for i = 1 to num_of_init_pt do
	(
		appendIfUnique StartPos #((random 1 xcount), (random 1 ycount), (random 1 zcount))
	)

	for i in StartPos do
	(
		append arr_trail #(i)
		set_status arr_cell i[1] i[2] i[3] false
	)
	create_shape arr_cell arr_trail StartPos num_of_init_pt
)

rollout labyrinth_maker_rlt "Labyrinth Maker v1.01" width:192 height:376
(
	GroupBox grp1 "Initial points" pos:[8,8] width:176 height:40
	label lbl1 "Number of points:" pos:[16,24] width:96 height:16
	spinner spn1 "" pos:[120,24] width:56 height:16 range:[1,100000,1] type:#integer
	
	GroupBox grp2 "Number of rows" pos:[8,56] width:176 height:88
	label lbl2 "X:" pos:[16,72] width:32 height:16
	label lbl3 "Y:" pos:[16,96] width:32 height:16
	label lbl4 "Z:" pos:[16,120] width:32 height:16
	checkbutton ckb1 " L" pos:[104,72] width:16 height:16
	spinner spn2 "" pos:[120,72] width:56 height:16 range:[1,100000,10] type:#integer
	spinner spn3 "" pos:[120,96] width:56 height:16 range:[1,100000,10] type:#integer
	spinner spn4 "" pos:[120,120] width:56 height:16 range:[1,100000,1] type:#integer
	
	GroupBox grp3 "Size" pos:[8,152] width:176 height:88
	label lbl5 "X:" pos:[16,168] width:32 height:16
	label lbl6 "Y:" pos:[16,192] width:32 height:16
	label lbl7 "Z:" pos:[16,218] width:32 height:16
	checkbutton ckb2 " L" pos:[104,168] width:16 height:16
	spinner spn5 "" pos:[120,168] width:56 height:16 range:[0,100000,10]
	spinner spn6 "" pos:[120,192] width:56 height:16 range:[0,100000,10]
	spinner spn7 "" pos:[120,216] width:56 height:16 range:[0,100000,10]
	checkbox chk1 "Enabled" pos:[16,264] width:72 height:16
	label lbl8 "Step:" pos:[17,288] width:32 height:16 enabled:false
	spinner spn8 "" pos:[120,288] width:56 height:16 range:[1,100000,1] type:#integer enabled:false 
	button btn1 "Generate" pos:[8,320] width:80 height:24
	button btn2 "Apply" pos:[96,320] width:40 height:24
	button btn3 "Clear" pos:[144,320] width:40 height:24
	
	GroupBox grp4 "Show generation in Viewport" pos:[8,248] width:176 height:64
	HyperLink hp1 "Bodyul Vladislav" pos:[62,352] width:112 height:16 address:"http://bodulwlpc.wix.com/ms-scripts" color:(color 0 180 250) hovercolor:(color 0 170 230) visitedcolor:(color 0 170 230)

	on ckb1 changed state do
	(
		if state then 
		(
			spn3.enabled = spn4.enabled = false
			spn3.value = spn4.value = spn2.value
		) else 
		(
			spn3.enabled = spn4.enabled = true
		)
	)
	
	on spn2 changed val do
	(
		if ckb1.state then
		(
			spn3.value = spn4.value = val
		)
	)
	
	on ckb2 changed state do
	(
		if state then 
		(
			spn6.enabled = spn7.enabled = false
			spn6.value = spn7.value = spn5.value
		) else 
		(
			spn6.enabled = spn7.enabled = true
		)
	)
	
	on spn5 changed val do
	(
		if ckb2.state then
		(
			spn6.value = spn7.value = val
		)
	)
	
	on chk1 changed state do
	(
		lbl8.enabled = spn8.enabled = state
	)
	
	on btn1 pressed do
	(
		start_gen()
	)
	
	on btn2 pressed do 
	(
		for i in $labyrinth_temp* do
		(
			i.name = (uniquename "labyrinth_")
		)
	)

	on btn3 pressed do 
	(
		delete $labyrinth_temp*
		max views redraw
	)
)
CreateDialog labyrinth_maker_rlt